/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.edu.psa.persistence;

import br.edu.psa.beans.exceptions.NonexistentEntityException;
import br.edu.psa.beans.exceptions.PreexistingEntityException;
import br.edu.psa.beans.exceptions.RollbackFailureException;
import br.edu.psa.model.Administrador;
import br.edu.psa.model.Cliente;
import java.io.Serializable;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.EntityNotFoundException;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import br.edu.psa.model.Pedido;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author JOAO e ANDRIGO
 */
public class ClienteJpaController extends Controller implements Serializable {

    public ClienteJpaController(EntityManager em) {
        this.setEntityManager(em);
    }

    public void create(Cliente cliente) throws PreexistingEntityException, RollbackFailureException, Exception {
        if (cliente.getPedidos() == null) {
            cliente.setPedidos(new ArrayList<Pedido>());
        }
        try {
            List<Pedido> attachedPedidos = new ArrayList<Pedido>();
            for (Pedido pedidosPedidoToAttach : cliente.getPedidos()) {
                pedidosPedidoToAttach = em.getReference(pedidosPedidoToAttach.getClass(), pedidosPedidoToAttach.getId());
                attachedPedidos.add(pedidosPedidoToAttach);
            }
            cliente.setPedidos(attachedPedidos);
            em.persist(cliente);
            for (Pedido pedidosPedido : cliente.getPedidos()) {
                Cliente oldClienteOfPedidosPedido = pedidosPedido.getCliente();
                pedidosPedido.setCliente(cliente);
                pedidosPedido = em.merge(pedidosPedido);
                if (oldClienteOfPedidosPedido != null) {
                    oldClienteOfPedidosPedido.getPedidos().remove(pedidosPedido);
                    oldClienteOfPedidosPedido = em.merge(oldClienteOfPedidosPedido);
                }
            }
        } catch (Exception ex) {
            if (findCliente(cliente.getId()) != null) {
                throw new PreexistingEntityException("Cliente " + cliente + " already exists.", ex);
            }
            throw ex;
        }
    }

    public void edit(Cliente cliente) throws NonexistentEntityException, RollbackFailureException, Exception {
        try {
            em = getEntityManager();
            Cliente persistentCliente = em.find(Cliente.class, cliente.getId());
            List<Pedido> pedidosOld = persistentCliente.getPedidos();
            List<Pedido> pedidosNew = cliente.getPedidos();
            List<Pedido> attachedPedidosNew = new ArrayList<Pedido>();
            for (Pedido pedidosNewPedidoToAttach : pedidosNew) {
                pedidosNewPedidoToAttach = em.getReference(pedidosNewPedidoToAttach.getClass(), pedidosNewPedidoToAttach.getId());
                attachedPedidosNew.add(pedidosNewPedidoToAttach);
            }
            pedidosNew = attachedPedidosNew;
            cliente.setPedidos(pedidosNew);
            cliente = em.merge(cliente);
            for (Pedido pedidosOldPedido : pedidosOld) {
                if (!pedidosNew.contains(pedidosOldPedido)) {
                    pedidosOldPedido.setCliente(null);
                    pedidosOldPedido = em.merge(pedidosOldPedido);
                }
            }
            for (Pedido pedidosNewPedido : pedidosNew) {
                if (!pedidosOld.contains(pedidosNewPedido)) {
                    Cliente oldClienteOfPedidosNewPedido = pedidosNewPedido.getCliente();
                    pedidosNewPedido.setCliente(cliente);
                    pedidosNewPedido = em.merge(pedidosNewPedido);
                    if (oldClienteOfPedidosNewPedido != null && !oldClienteOfPedidosNewPedido.equals(cliente)) {
                        oldClienteOfPedidosNewPedido.getPedidos().remove(pedidosNewPedido);
                        oldClienteOfPedidosNewPedido = em.merge(oldClienteOfPedidosNewPedido);
                    }
                }
            }
        } catch (Exception ex) {
            String msg = ex.getLocalizedMessage();
            if (msg == null || msg.length() == 0) {
                Long id = cliente.getId();
                if (findCliente(id) == null) {
                    throw new NonexistentEntityException("The cliente with id " + id + " no longer exists.");
                }
            }
            throw ex;
        }
    }

    public void destroy(Long id) throws NonexistentEntityException, RollbackFailureException, Exception {

        Cliente cliente;
        try {
            cliente = em.getReference(Cliente.class, id);
            cliente.getId();
        } catch (EntityNotFoundException enfe) {
            throw new NonexistentEntityException("The cliente with id " + id + " no longer exists.", enfe);
        }
        List<Pedido> pedidos = cliente.getPedidos();
        for (Pedido pedidosPedido : pedidos) {
            pedidosPedido.setCliente(null);
            pedidosPedido = em.merge(pedidosPedido);
        }
        em.remove(cliente);
    }

    public List<Cliente> findClienteEntities() {
        return findClienteEntities(true, -1, -1);
    }

    public List<Cliente> findClienteEntities(int maxResults, int firstResult) {
        return findClienteEntities(false, maxResults, firstResult);
    }

    private List<Cliente> findClienteEntities(boolean all, int maxResults, int firstResult) {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        cq.select(cq.from(Cliente.class));
        Query q = em.createQuery(cq);
        if (!all) {
            q.setMaxResults(maxResults);
            q.setFirstResult(firstResult);
        }
        return q.getResultList();
    }

    public Cliente findCliente(Long id) {
        return em.find(Cliente.class, id);
    }

    public int getClienteCount() {
        CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
        Root<Cliente> rt = cq.from(Cliente.class);
        cq.select(em.getCriteriaBuilder().count(rt));
        Query q = em.createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }

    public Cliente findCliente(String email, String password) {
        StringBuilder sql = new StringBuilder();
        sql.append("select c from Cliente c where c.email = :email and c.senha = :password");
        Query query = em.createQuery(sql.toString());
        query.setParameter("email", email);
        query.setParameter("password", password);
        Cliente c = (Cliente) query.getSingleResult();
        return c;
    }
}
